/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is ThumbsDown.
 *
 * The Initial Developer of the Original Code is Atte Kemppilä.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


const EXPORTED_SYMBOLS = ["ThumbsDown"];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");

Cu.import("resource://thumbsdown/util.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "Context", "resource://thumbsdown/Context.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadManager", "resource://thumbsdown/DownloadManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ScriptEval", "resource://thumbsdown/ScriptEval.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ScriptManager", "resource://thumbsdown/ScriptManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ScriptStore", "resource://thumbsdown/ScriptStore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Thumbnail", "resource://thumbsdown/Thumbnail.jsm");

const SCRIPT_RECORD_PROPS = "name type subType thumbnailType thumbnailPattern linkType linkExpr linkPattern action1 action2".split(" ");


const ThumbsDown =
{
    EXT_ID: "thumbsdown@mozdev.org",
    SCHEME: "thumbsdown",
    
    get ScriptManager()
    {
        return ScriptManager;
    },
    
    get ScriptStore()
    {
        ScriptStore.open();
        return ScriptStore;
    },
    
    get schemaVersion()
    {
        return ScriptStore._options.schemaVersion;
    },
    
    getThumbnails: function(node)
    {
        return Thumbnail.getThumbnails(node);
    },
    
    newContext: function()
    {
        return new Context();
    },
    
    getDownloadManager: function(callback)
    {
        let params =
        {
            dir: ThumbsDown.prefs.getComplexValue("downloadDir", Ci.nsISupportsString).data,
        };
        
        let self = this;
        let error = function(e) { self._handleDownloadManagerError(e); };
        
        DownloadManager.create(params, callback, error);
    },
    
    _handleDownloadManagerError: function(e)
    {
        let window = null;
        let title = _("error.title");
        let msg = _("error.download", e.message);
        Services.prompt.alert(window, title, msg);
        Cu.reportError(e);
    },
    
    eval: function(thumbCtxs, callback)
    {
        ScriptEval.eval(thumbCtxs, callback);
    },
    
    copyScriptsToClipboard: function(records)
    {
        let specs = [this.getScriptUri(record).spec for each (record in records)];
        let text = specs.join("\n");
        Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper).copyString(text);
    },
    
    getScriptUri: function(record)
    {
        let data = {};
        data.version = ThumbsDown.schemaVersion;
        
        for each (let prop in SCRIPT_RECORD_PROPS)
            if (record[prop])
                data[prop] = record[prop];
        
        let uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
        uri.spec = ThumbsDown.SCHEME + ":" + JSON.stringify(data);
        return uri;
    },
    
    installScript: function(thumbsdownUri, docUri, context)
    {
        try
        {
            let json = thumbsdownUri.path;
            let data = JSON.parse(decodeURI(json));
            let record = ThumbsDown.sanitizeScript(data);
            
            let browser = context;
            let win = browser.ownerDocument.defaultView;
            
            let host = docUri.host;
            let scriptName = record.name;
            let callback = function() { ThumbsDown.openScriptDialog("add", null, record) };
            
            win.PopupNotifications.show(
                browser,
                "thumbsdown_install_popup",
                _("install.message", host, scriptName),
                "thumbsdown_notification_icon",
                {label: _("install.action.open"), accessKey: _("install.action.open_key"), callback: callback},
                null,  // secondaryActions
                {removeOnDismissal: true});
        }
        catch (e)
        {
            Cu.reportError(e);
        }
    },
    
    sanitizeScript: function(record)
    {
        if (! (record && (typeof(record) == "object")))
            throw new Error("script is not object");
        
        if (record.version !== ThumbsDown.schemaVersion)
            throw new Error("script has incompatible version: " + record.version);
        
        if (! (("name" in record) && (typeof(record.name) == "string") && record.name.trim()))
            throw new Error("script has no name");
        
        let sanitized = {};
        for each (let prop in SCRIPT_RECORD_PROPS)
            if (prop in record)
                sanitized[prop] = record[prop];
        
        return sanitized;
    },
    
    openHomePage: function()
    {
        var self = this;
        AddonManager.getAddonByID(ThumbsDown.EXT_ID, function(ext) { openUrls([ext.homepageURL]); });
    },
    
    openPrefWindow: function(pane)
    {
        let instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply");
        
        openWindow({
            url: "chrome://thumbsdown/content/options.xul",
            name: "thumbsdown_prefwindow",
            features: "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal"),
            args: (pane ? ["prefpane_" + pane] : null), 
            callback: (pane ? function(win) { win.document.documentElement.showPane(win.document.getElementById("prefpane_" + pane)); } : null),
        });
    },
    
    openScriptDialog: function(operation, scriptId, record)
    {
        let name = ((operation == "set") ? "thumbsdown_scriptDialog_"  + scriptId : null);
        
        openWindow({
            url: "chrome://thumbsdown/content/manager/script.xul",
            name: name,
            features: "chrome,resizable",
            args: {operation: operation, scriptId: scriptId, record: record},
        });
    },
    
    openScriptManagerWindow: function()
    {
        openWindow({
            url: "chrome://thumbsdown/content/manager/manager.xul",
            name: "thumbsdown_scriptManager",
            features: "chrome,resizable",
        });
    },
    
    openScriptRunnerWindow: function(focus)
    {
        focus = ((arguments.length > 0) ? focus : ThumbsDown.prefs.getBoolPref("scriptrunner.focus"));
        
        openWindow({
            url: "chrome://thumbsdown/content/scriptrunner.xul",
            name: "thumbsdown_scriptRunner",
            features: "chrome,resizable",
            focus: focus,
        });
    },
    
    openScriptWizard: function(contentDocument)
    {
        openWindow({
            url: "chrome://thumbsdown/content/scriptwizard/scriptwizard.xul",
            name: "thumbsdown_scriptWizard",
            features: "chrome,resizable",
            args: [contentDocument],
        });
    },
}


XPCOMUtils.defineLazyGetter(this, "_", function()
{
    let bundleUrl = "chrome://thumbsdown/locale/thumbsdown.properties";
    let bundle = Services.strings.createBundle(bundleUrl);
    return getStringBundleGetter(bundle);
});

XPCOMUtils.defineLazyGetter(ThumbsDown, "prefs", function()
{
    return Services.prefs.getBranch("extensions.thumbsdown.");
});
